from util.expy import path_append
path_append("runtime", __file__)

import hid
import numpy as np

from util.base import Deletable
from util.log import getLogger
logger = getLogger(10)

BLOCK_TIMEOUT = 500
HID_PACK_LEN = 64
BYTES_PACK_HEAD = bytes([0x80, 0x2e, 0x2e, 0x80])
BYTES_PACK_TAIL = bytes([0x2e, 0x80, 0x80, 0x2e])

def bytes2int(bytes_):
    return int.from_bytes(bytes_, "little")

def list2pack(list_):
    """ 用于补充数据至65位 """
    # 写入时，包长为65：1位ID+64位数据
    len_list = len(list_)
    if len_list > HID_PACK_LEN:
        pass
        # yield list_[:64]
        # return list2pack(list_[64:])  # 递归
    else:
        len_remain = HID_PACK_LEN - len_list
        print(len_remain)
        return list_ + [0]*len_remain

def extract_img(bytes_data: bytearray):
    if isinstance(bytes_data, bytes):
        bytes_data = bytearray(bytes_data)
    barcode_len = bytes2int(bytes_data[8:10])
    # img_size = bytes2int(bytes_data[16:20])
    img_width = bytes2int(bytes_data[12:14])
    img_height = bytes2int(bytes_data[14:16])

#     logger.debug(f"""barcode_len: {barcode_len}
# img_width: {img_width}
# img_height: {img_height}
# """)

    start = HID_PACK_LEN +256 + barcode_len
    end = start + img_height * img_width
    img_data = bytes_data[start:end]

    img = np.asarray(img_data, dtype=np.int8)
    img = img.reshape(img_height, img_width)
    return img


class HerosysHidDevice(Deletable):
    def __init__(self):
        super().__init__()

        self.hid = hid.device()
        self.hid.open(0xBACF, 0xBDDC)  # (47823, 48604)
        self.hid_info()

        # self.hid.set_nonblocking(True)
        self.send_active_cmd()

    def send_active_cmd(self):
        # cmd_id = 0  # HID的Msg-ID
        # cmd_conn = [cmd_id, 0x2e, 0x80, 0x80, 0x2e] + list(b"Read")  # 2e80802e52656164
        cmd_conn = [0, 46, 128, 128, 46, 82, 101, 97, 100]
        self.hid.write(cmd_conn)  # if done, return 65
        self.read()  # 返回【参数区】数据

    def destroy(self):
        logger.debug("关闭HID连接")
        self.hid.close()

    def hid_info(self):
        print("Manufacturer: %s" % self.hid.get_manufacturer_string())
        print("Product: %s" % self.hid.get_product_string())
        print("Serial No: %s" % self.hid.get_serial_number_string())

    def read(self):
        """ 阻塞读取消息 """
        bytes_data = bytearray()
        while True:
            pack = self.hid.read(HID_PACK_LEN, timeout_ms=BLOCK_TIMEOUT)
            if not pack:
                if bytes_data:  continue
                else:  break
            pack = bytearray(pack)

            index = pack.find(BYTES_PACK_TAIL)
            if index < 0:
                bytes_data += pack
            else:
                bytes_data += pack[:index+4]
                # BYTES_PACK_TAIL可能出现在两个64位包直接
                # 理应查找……这里直接忽略
                break

            # 最大包长检测（如果一直未收到有效结束符）……忽略

        # check header
        if bytes_data and bytes_data[:4] != BYTES_PACK_HEAD:
            logger.debug(f"非法的HID数据头：【{bytes(bytes_data[:10])}】")
            return None
            # 尝试二次查找有效数据……这里忽略
            # offset = bytes_data.find(BYTES_PACK_HEAD)
            # if offset > 0:
            #     logger.debug("已修复数据包")
            #     bytes_data = bytes_data[offset:]
            #     return bytes_data

        # logger.debug(f"获取到HID数据，Length：【{len(bytes_data)}】")
        return bytes_data


if __name__ == "__main__":
    hid = HerosysHidDevice()
    hid.hid.set_nonblocking(False)  # 设为阻塞
    n = 10
    while n:
        data = hid.read()
        n -= 1
    extract_img(data)
